#pragma once
#include <libmesh/vector_value.h>
#include <libmesh/point.h>

#include <complex>
#include <memory>
#include <vector>

namespace cem
{

struct LayerDepthConduction; // forward decl (defined in parameter_reader.h)
struct BoundarySpec;         // forward decl (defined in boundary_condition.h)

namespace boundary
{

// 分层表面阻抗（TE 近似）
std::complex<double>
compute_surface_impedance_from_layers(const std::vector<LayerDepthConduction> & layers,
                                      double omega);

// 给定单位法向量，构造一个稳定的单位切向量
libMesh::RealVectorValue compute_unit_tangent(const libMesh::RealVectorValue & n);

// -----------------------------------------------------------------------------
// 策略接口: 边界幅值与方向
// -----------------------------------------------------------------------------

// 类: BoundaryAmplitudeProvider
// 作用: 按给定的边界规格（在工厂中解析）与系统背景（层化/频率）生成可复用的复数幅值提供者。
// 说明: 建议在构造时完成必要预计算，compute_scalar() 为只读、无副作用。
class BoundaryAmplitudeProvider
{
public:
    virtual ~BoundaryAmplitudeProvider() = default;

    // 函数: compute_scalar
    // 作用: 返回该边界在当前设置下的复数幅值（与积分点无关）。
    virtual std::complex<double> compute_scalar() const = 0;

    // 函数: compute_at_point
    // 参数: p - 积分点的空间坐标
    // 作用: 返回该积分点处的复数幅值（默认回退为常量幅值）。
    virtual std::complex<double> compute_at_point(const libMesh::Point & p) const
    {
        (void)p; // 未使用
        return compute_scalar();
    }
};

// 类: BoundaryDirectionProvider
// 作用: 根据积分点法向返回对应的切向单位向量（若指定了方向，则先投影到切平面后归一化）。
class BoundaryDirectionProvider
{
public:
    virtual ~BoundaryDirectionProvider() = default;

    // 函数: compute_direction
    // 参数: normal - 积分点处单位法向
    // 返回: 该处切向单位向量（稳定、可复用）。
    virtual libMesh::RealVectorValue
    compute_direction(const libMesh::RealVectorValue & normal) const = 0;
};

// 工厂函数: 根据 spec 选择具体的策略对象。
// 说明: 按需捕获 layers/omega 或方向向量，避免在装配循环中重复分支判断。
std::unique_ptr<BoundaryAmplitudeProvider> make_amplitude_provider(
    const BoundarySpec & spec, const std::vector<LayerDepthConduction> & layers, double omega);

std::unique_ptr<BoundaryDirectionProvider> make_direction_provider(const BoundarySpec & spec);

} // namespace boundary

} // namespace cem